package server.connector;

import org.apache.catalina.*;
import org.apache.catalina.connector.Constants;
import org.apache.catalina.util.Enumerator;
import org.apache.catalina.util.RequestUtil;
import org.apache.catalina.util.StringManager;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import java.io.*;
import java.net.Socket;
import java.util.*;

public abstract class RequestBase implements Request, ServletRequest {
    protected String remoteHost = null;
    public void setRemoteHost(String remoteHost) {
        this.remoteHost = remoteHost;
    }
    //实现Request接口------------------------------------------------------------------
    protected String authorization = null;
    @Override
    public String getAuthorization() {
        return authorization;
    }

    @Override
    public void setAuthorization(String authorization) {
        this.authorization = authorization;
    }
    protected Connector connector = null;
    @Override
    public Connector getConnector() {
        return connector;
    }

    @Override
    public void setConnector(Connector connector) {
        this.connector = connector;
    }

    protected Context context = null;
    @Override
    public Context getContext() {
        return context;
    }

    @Override
    public void setContext(Context context) {
        this.context = context;
    }

    protected static final String info = "server.connector.RequestBase/1.0";
    @Override
    public String getInfo() {
        return info;
    }

    protected RequestFacade facade = new RequestFacade(this);
    @Override
    public ServletRequest getRequest() {
        return facade;
    }

    protected Response response = null;
    @Override
    public Response getResponse() {
        return response;
    }

    @Override
    public void setResponse(Response response) {
        this.response = response;
    }
    protected Socket socket = null;
    @Override
    public Socket getSocket() {
        return socket;
    }

    @Override
    public void setSocket(Socket socket) {
        this.socket = socket;
    }

    protected InputStream input = null;
    @Override
    public InputStream getStream() {
        return input;
    }

    @Override
    public void setStream(InputStream stream) {
        this.input = input;
    }

    protected Wrapper wrapper = null;
    @Override
    public Wrapper getWrapper() {
        return wrapper;
    }

    @Override
    public void setWrapper(Wrapper wrapper) {
        this.wrapper = wrapper;
    }

    @Override
    public ServletInputStream createInputStream() throws IOException {
        return new RequestStream(this);
    }

    protected BufferedReader reader = null;
    protected ServletInputStream stream = null;
    @Override
    public void finishRequest() throws IOException {
        if (reader != null) {
            try {
                reader.close();
            } catch (IOException e) {
                ;
            }
        }
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException e) {
                ;
            }
        }
    }

    private transient HashMap notes = new HashMap();
    @Override
    public Object getNote(String name) {
        synchronized (notes) {
            return (notes.get(name));
        }
    }

    @Override
    public Iterator getNoteNames() {
        synchronized (notes) {
            return (notes.keySet().iterator());
        }
    }

    @Override
    public void recycle() {
        attributes.clear();
        authorization = null;
        characterEncoding = null;
        // connector is NOT reset when recycling
        contentLength = -1;
        contentType = null;
        context = null;
        input = null;
        locales.clear();
        notes.clear();
        protocol = null;
        reader = null;
        remoteAddr = null;
        remoteHost = null;
        response = null;
        scheme = null;
        secure = false;
        serverName = null;
        serverPort = -1;
        socket = null;
        stream = null;
        wrapper = null;
    }

    @Override
    public void removeNote(String name) {
        synchronized (notes) {
            notes.remove(name);
        }
    }

    protected int contentLength = -1;
    @Override
    public void setContentLength(int length) {
        this.contentLength = length;
    }

    protected String contentType = null;
    protected String characterEncoding = null;
    @Override
    public void setContentType(String type) {
        this.contentType = type;
        if (type.indexOf(';') >= 0)
            characterEncoding = RequestUtil.parseCharacterEncoding(type);
    }

    @Override
    public void setNote(String name, Object value) {
        synchronized (notes) {
            notes.put(name, value);
        }
    }

    protected String protocol = null;
    @Override
    public void setProtocol(String protocol) {
        this.protocol = protocol;
    }

    protected String remoteAddr = null;
    @Override
    public void setRemoteAddr(String remoteAddr) {
        this.remoteAddr = remoteAddr;
    }

    protected String scheme = null;
    @Override
    public void setScheme(String scheme) {
        this.scheme = scheme;
    }

    protected boolean secure = false;
    @Override
    public void setSecure(boolean secure) {
        this.secure = secure;
    }

    protected String serverName = null;
    @Override
    public void setServerName(String name) {
        this.serverName = name;
    }

    protected int serverPort = -1;
    @Override
    public void setServerPort(int port) {
        this.serverPort = port;
    }


    //实现ServletRequest接口------------------------------------------------------------------
    protected HashMap attributes = new HashMap();
    @Override
    public Object getAttribute(String name) {
        synchronized (attributes) {
            return (attributes.get(name));
        }
    }

    @Override
    public Enumeration getAttributeNames() {
        synchronized (attributes) {
            return (new Enumerator(attributes.keySet()));
        }
    }

    @Override
    public String getCharacterEncoding() {
        return (this.characterEncoding);
    }

    @Override
    public void setCharacterEncoding(String enc) throws UnsupportedEncodingException {
        byte buffer[] = new byte[1];
        buffer[0] = (byte) 'a';
        String dummy = new String(buffer, enc);

        // Save the validated encoding
        this.characterEncoding = enc;
    }

    @Override
    public int getContentLength() {
        return (this.contentLength);
    }

    @Override
    public String getContentType() {
        return (contentType);
    }

    @Override
    public ServletInputStream getInputStream() throws IOException {
        if (reader != null)
            throw new IllegalStateException
                    (sm.getString("requestBase.getInputStream.ise"));

        if (stream == null)
            stream = createInputStream();
        return (stream);
    }

    protected static StringManager sm =
            StringManager.getManager(Constants.Package);

    @Override
    public abstract String getParameter(String s);

    @Override
    public abstract Enumeration getParameterNames() ;

    @Override
    public abstract String[] getParameterValues(String s);

    @Override
    public abstract Map getParameterMap();

    @Override
    public String getProtocol() {
        return protocol;
    }

    @Override
    public String getScheme() {
        return (this.scheme);
    }

    @Override
    public String getServerName() {
        return (this.serverName);
    }

    @Override
    public int getServerPort() {
        return (this.serverPort);
    }

    @Override
    public BufferedReader getReader() throws IOException {
        if (stream != null)
            throw new IllegalStateException
                    (sm.getString("requestBase.getReader.ise"));

        if (reader == null) {
            String encoding = getCharacterEncoding();
            if (encoding == null)
                encoding = "ISO-8859-1";
            InputStreamReader isr =
                    new InputStreamReader(createInputStream(), encoding);
            reader = new BufferedReader(isr);
        }
        return (reader);
    }

    @Override
    public String getRemoteAddr() {
        return (this.remoteAddr);
    }

    @Override
    public String getRemoteHost() {
        return (this.remoteHost);
    }

    @Override
    public void setAttribute(String name, Object value) {
        // Name cannot be null
        if (name == null)
            throw new IllegalArgumentException
                    (sm.getString("requestBase.setAttribute.namenull"));

        // Null value is the same as removeAttribute()
        if (value == null) {
            removeAttribute(name);
            return;
        }

        synchronized (attributes) {
            attributes.put(name, value);
        }
    }

    @Override
    public void removeAttribute(String name) {
        synchronized (attributes) {
            attributes.remove(name);
        }
    }

    protected static Locale defaultLocale = Locale.getDefault();
    protected ArrayList locales = new ArrayList();
    @Override
    public Locale getLocale() {
        synchronized (locales) {
            if (locales.size() > 0)
                return ((Locale) locales.get(0));
            else
                return (defaultLocale);
        }
    }

    @Override
    public Enumeration getLocales() {
        synchronized (locales) {
            if (locales.size() > 0)
                return (new Enumerator(locales));
        }
        ArrayList results = new ArrayList();
        results.add(defaultLocale);
        return (new Enumerator(results));
    }

    @Override
    public boolean isSecure() {
        return (this.secure);
    }

    @Override
    public abstract RequestDispatcher getRequestDispatcher(String path);


    @Override
    public String getRealPath(String path) {
        if (context == null)
            return (null);
        ServletContext servletContext = context.getServletContext();
        if (servletContext == null)
            return (null);
        else {
            try {
                return (servletContext.getRealPath(path));
            } catch (IllegalArgumentException e) {
                return (null);
            }
        }
    }


}
